import * as THREE from '../../../assets/three/build/three.module.js';
import {GLTFLoader} from '../../../assets/three/examples/jsm/loaders/GLTFLoader.js';
import {FBXLoader} from '../../../assets/three/examples/jsm/loaders/FBXLoader.js';
import {EffectComposer} from "../../../assets/three/examples/jsm/postprocessing/EffectComposer.js";
import {RenderPass} from '../../../assets/three/examples/jsm/postprocessing/RenderPass.js';
import {ShaderPass} from "../../../assets/three/examples/jsm/postprocessing/ShaderPass.js";
import {FXAAShader} from "../../../assets/three/examples/jsm/shaders/FXAAShader.js";
import {OutlinePass} from '../../../assets/three/examples/jsm/postprocessing/OutlinePass.js';


function oRender_ThreeEngine(engine) {
  this.engine = engine;
}

oRender_ThreeEngine.prototype = {
  // 渲染FBX文件
  loadFBX: function (model, materialCallback, callback) {
    let o = this;
    // fbx model
    const loader = new FBXLoader();
    loader.load(model.url, function (object) {
      // o.ObjectList.push({name: model.name, model: object});
      // 动画执行
      // let mixer = new THREE.AnimationMixer(object);
      // const action = mixer.clipAction(object.animations[0]);
      // action.play();

      // 位置
      if (model.position) {
        object.position.x = model.position.x;    //
        object.position.y = model.position.y;    // 高度
        object.position.z = model.position.z;
      }
      // 旋转，有些模型自带旋转角度，这里的设计用于叠加旋转。
      if (model.rotation) {
        object.rotation.x += model.rotation.x;
        object.rotation.y += model.rotation.y;
        object.rotation.z += model.rotation.z;
      }

      object.scale.multiplyScalar(model.size || 1); //缩放

      // console.log(object);
      object.traverse(function (child) {
        if (child.isMesh) {
          // 设置fbx模型接收的曝光度。
          child.material.emissive = new THREE.Color(1, 1, 1);
          child.material.emissiveIntensity = 0.4;
          child.material.emissiveMap = child.material.map;
          // 清除灰度纹理及设置side属性
          child.material.alphaMap = null;          // 这个必须干掉，是3DMax的产物，在WebGL中会导致异常。
          child.material.side = THREE.DoubleSide;  // side，属性控制渲染前面、后面、全部:2:THREE.DoubleSide

          // console.log(child.material.color);
          // 模型转线框技术
          // child.material = new THREE.MeshPhongMaterial({color: "#161616", opacity: 1});
          // child.material.wireframe = true;

          // 读取模型原始颜色代码，重新赋值，这里可以加个判断，有纹理的就不用原始颜色。
          // child.material = new THREE.MeshPhongMaterial({color: child.material.color, opacity: 1});

          // 如果有材质,后续可支持按分组替换。
          if (model.material) {
            child.material = model.material.data;
          }

          child.castShadow = true; // 产生阴影，会产生波浪
          child.receiveShadow = true;
          // console.log(child.name);
          if (model.opacity) {

            // 还是要想办法解决这个问题 或者 找到对应的纹理模型，可以考虑用射线进行捕捉。
            // if (child.material.name && child.material.name.indexOf("0019") > -1) {
            // child.material.visible = false;
            // console.log(child);
            // }
            // console.log(child);
            child.material.transparent = true; // 只有树可以开启，否则建筑模型会导致png贴图的墙壁变透明
            child.material.opacity = model.opacity;
            // child.material.side = THREE.DoubleSide;
            // child.material.depthTest = false;

          }
          // 子模块隐藏。
          // if (model.name.indexOf("wk") > -1) {
          //   if (child.name.indexOf("WKDXW0") > -1) {
          //     console.log(child);
          //     child.visible = false;
          //   }
          // }

          // 追加轮廓线，可适用于射线追踪器。outline
          if (model.outline) {
            // let outlineMaterial = new THREE.LineBasicMaterial({color: "#4f4b4c", linewidth: 2,});
            // // console.log(outlineMaterial);
            // let lineGeometry = new THREE.EdgesGeometry(child.geometry, 45);
            // let line = new THREE.LineSegments(lineGeometry, outlineMaterial);
            // child.add(line);
            o.setOutLine(child, "#4f4b4c");
          }

          // 追加素材，object打包出来不含素材。
          if (materialCallback) {
            // 将模型参数、模型对象、每个建面返回。
            materialCallback(model, object, child);
          }
          // o.ObjectList.push({name: model.name, model: object, material: child.material});

        } else {
          // child.visible = false;
          // console.log(child);
        }
      });

      // o.scene.add(object);
      // setTimeout(function () {
      //   o.render();
      // }, 500);

      // 创建完成，返回对象。
      if (callback) {
        callback(object);
      }

    });
  },
  // GLB and GLTF 不支持模型透明度设置，官网案例也是如此。
  loadGLB: function (model, materialCallback, callback) {
    // 加载模型
    // let loader = new GLTFLoader(manager);
    let loader = new GLTFLoader();

    if (model.isDraco) {
      // alert(JSON.stringify(model));
      const dracoLoader = new DRACOLoader(); //
      dracoLoader.setDecoderPath("/static/resource/script/component/three/draco/gltf/");
      //设置解压库文件路径
      dracoLoader.setDecoderConfig({type: "js"}); //使用js方式解压
      dracoLoader.preload();
      // const dracoLoader = new DRACOLoader(); //
      loader.setDRACOLoader(dracoLoader); //gltfloader使用dracoLoader

      //加载压缩模型js
      // const dracoLoader = new DRACOLoader(); //
      // dracoLoader.setDecoderPath("/static/resource/script/component/three/draco/gltf/"); //设置解压库文件路径
      // dracoLoader.setDecoderConfig({type: "js"}); //使用js方式解压
      // //dracoLoader.preload()  //初始化_initDecoder 解码器
      // loader.setDRACOLoader(dracoLoader); //gltfloader使用dracoLoader
    }

    // 设置gltfloader解压loader
    loader.load(model.url, function (gltf) {
      // 位置
      if (model.position) {
        gltf.scene.position.x = model.position.x;    //
        gltf.scene.position.y = model.position.y;    // 高度
        gltf.scene.position.z = model.position.z;
      }
      // 旋转
      if (model.rotation) {
        gltf.scene.rotation.x = model.rotation.x;
        gltf.scene.rotation.y = model.rotation.y;
        gltf.scene.rotation.z = model.rotation.z;
      }

      gltf.scene.scale.multiplyScalar(model.size || 1); //缩放

      // gltf.scene.translateX = 100;
      // console.log("==========");
      // console.log(gltf);
      // gltf.transparent = true;
      // gltf.opacity = 0.5;

      // 遍历子网格，您需要在每个子网格上设置 castShadow = true ，如下所示：
      gltf.scene.traverse(function (child) {
        if (child instanceof THREE.Mesh) {
          // console.log(node);
          child.castShadow = true;
          child.receiveShadow = true;
          // child.visible = false; // glb、gltf只支持visible，fbx才能支持透明度
          // child.material.side = THREE.DoubleSide;
          // child.material.transparent = true;
          // child.material.opacity = 0.5;
          child.material.needsUpdate = true;

          // o.GroupList.push(child);
        }

        // if (child.isMesh) {
        //   //设置mesh的一些属性（比如透明度）
        //   child.material.transparent = true;
        //   child.material.opacity = 0.5;
        // }

        if (materialCallback) {
          // 将模型参数、模型对象、每个建面返回。
          materialCallback(model, gltf, child);
        }
      });

      // gltf.scene.children[0].material.transparent = true;
      // gltf.scene.children[0].material.opacity = 0.1;

      // scene.add(gltf.scene);

      // 创建完成，返回对象。
      if (callback) {
        callback(gltf.scene);
      }
    });

    // loader.castShadow = true; // 添加阴影
  },
  // 设置对象边框：https://blog.csdn.net/arvin0/article/details/121613144
  setBorder: function (object, renderer, scene, camera) {
    console.log(object);

    const size = renderer.getSize(new THREE.Vector2());
    const _pixelRatio = renderer.getPixelRatio();
    const _width = size.width;
    const _height = size.height;
    const renderTarget = new THREE.WebGLRenderTarget(
      _width * _pixelRatio,
      _height * _pixelRatio,
      {
        minFilter: THREE.LinearFilter,
        magFilter: THREE.LinearFilter,
        format: THREE.RGBAFormat,
        encoding: THREE.sRGBEncoding
      }
    );

    // ThreeJS 136 版本
    let composer = new EffectComposer(renderer, renderTarget);

    const renderPass = new RenderPass(scene, camera);
    composer.addPass(renderPass);

    // 使用 outlinePass 技法
    let outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera, object);
    composer.addPass(outlinePass);

    let effectFXAA = new ShaderPass(FXAAShader);
    effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
    composer.addPass(effectFXAA);

    outlinePass.selectedObjects = object;
    outlinePass.visibleEdgeColor.set(new THREE.Color("#9b160e")); // 边缘可见部分发颜色 sColor[0].color
    outlinePass.hiddenEdgeColor.set(new THREE.Color("#0e28a6")); // 边缘遮挡部分发光颜色 sColor[1].color
    outlinePass.edgeStrength = Number(10.0); //边框的亮度
    outlinePass.edgeGlow = Number(1); //光晕[0,1]
    outlinePass.edgeThickness = Number(1.0); //边缘浓度
    outlinePass.pulsePeriod = Number(1.8); //呼吸闪烁的速度 闪烁频率 ，默认0 ，值越大频率越低
    outlinePass.usePatternTexture = false; //是否使用父级的材质
    outlinePass.downSampleRatio = 2; // 边框弯曲度
    outlinePass.clear = true;

    // animate render里
    renderer.render(scene, camera);
    composer.render();


    // 创建一个EffectComposer（效果组合器）对象，然后在该对象上添加后期处理通道。
    // this.composer = new EffectComposer(this.renderer);
    // // 新建一个场景通道  为了覆盖到原理来的场景上
    // this.renderPass = new RenderPass(this.scene, this.camera);
    // this.composer.addPass(this.renderPass);
    // // 物体边缘发光通道
    // this.outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), this.scene, this.camera, selectedObjects);
    // this.outlinePass.selectedObjects = selectedObjects;
    // this.outlinePass.edgeStrength = 10.0 // 边框的亮度
    // this.outlinePass.edgeGlow = 1// 光晕[0,1]
    // this.outlinePass.usePatternTexture = false // 是否使用父级的材质
    // this.outlinePass.edgeThickness = 1.0 // 边框宽度
    // this.outlinePass.downSampleRatio = 1 // 边框弯曲度
    // this.outlinePass.pulsePeriod = 5 // 呼吸闪烁的速度
    // this.outlinePass.visibleEdgeColor.set(parseInt(0x00ff00)) // 呼吸显示的颜色
    // this.outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0) // 呼吸消失的颜色
    // this.outlinePass.clear = true
    // this.composer.addPass(this.outlinePass)
    // // 自定义的着色器通道 作为参数
    // let effectFXAA = new ShaderPass(FXAAShader);
    // effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight)
    // effectFXAA.renderToScreen = true
    // this.composer.addPass(effectFXAA);
  },
  // 给指定模型增加轮廓线
  setOutLine: function (mesh, color) {
    let outlineMaterial = new THREE.LineBasicMaterial({color: color, linewidth: 5,});
    // console.log(outlineMaterial);
    let lineGeometry = new THREE.EdgesGeometry(mesh.geometry, 45);
    let line = new THREE.LineSegments(lineGeometry, outlineMaterial);
    mesh.add(line);

    return mesh;
  }
}

export {
  oRender_ThreeEngine
}


